// Copyright 2020 The XLS Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef XLS_CONTRIB_ICE40_IO_STRATEGY_H_
#define XLS_CONTRIB_ICE40_IO_STRATEGY_H_

#include <vector>

#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "xls/codegen/vast/vast.h"
#include "xls/simulation/verilog_include.h"

namespace xls {
namespace verilog {

// Represents a pluggable strategy for wiring up I/O in the uncore.
//
// The I/O strategy gets to add top-level dependencies (e.g. sourcing top-level
// pins from the outside world), then is asked to instantiate I/O blocks for
// communicating the byte transport (via output.tx_byte and input.rx_byte).
//
// The ready/valid signaling presented here (in the Input / Output types) is the
// way host I/O is exposed to the uncore.
class IOStrategy {
 public:
  // Signals related to sending output (i.e. to the host).
  //
  // These connect to the top-level state machine that manages device RPCs.
  struct Output {
    // Byte to transfer to the host (driven externally, into the I/O block).
    LogicRef* tx_byte;
    // Whether tx_byte holds valid data (driven externally, into the I/O block).
    LogicRef* tx_byte_valid;
    // Signals that the transmitter is done processing the tx_byte value and is
    // ready to receive a new value (driven internally, from the I/O block).
    LogicRef* tx_byte_ready;
  };

  // Signals related to accepting input (i.e. from the host).
  //
  // These connect to the top-level state machine that manages device RPCs.
  struct Input {
    // Byte that has been received from the host (driven from the I/O block).
    LogicRef* rx_byte;
    // Whether rx_byte contains valid data (driven from the I/O block).
    LogicRef* rx_byte_valid;
    // Signals that the device is done processing the rx_byte value (driven
    // externally).
    LogicRef* rx_byte_done;
  };

  virtual ~IOStrategy() = default;

  // Adds any top-level signals as input/output ports of "m" that are required
  // for the I/O.
  //
  // For example, on ICE40 this ensures that the tx/rx signals are present on
  // the top level of the design for binding to those known top-level pins.
  virtual absl::Status AddTopLevelDependencies(LogicRef* clk, Reset reset,
                                               Module* m) = 0;

  // Instantiates transmitter/receiver blocks that operate in byte-wise fashion
  // and connects them to the "input" and "output" signals.
  virtual absl::Status InstantiateIOBlocks(Input input, Output output,
                                           Module* m) = 0;

  // Returns the set of inclusions tick-included by the Verilog generated by the
  // IO strategy. Each VerilogInclude specifies the relative path that the file
  // is included with (eg, "foo/bar.v" for "`include "foo/bar.v") and the
  // Verilog text of the included file.
  virtual absl::StatusOr<std::vector<VerilogInclude>> GetIncludes() = 0;
};

}  // namespace verilog
}  // namespace xls

#endif  // XLS_CONTRIB_ICE40_IO_STRATEGY_H_
